#!/usr/bin/env python
#
#       Interfaces.py
#       
#       Copyright 2009 Ben Davis <its.hip@gmail.com>, Pete Lord <mr.petelord@gmail.com>, Robin Hayes <bonzairob@gmail.com>
#       
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#       
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#       
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.

import os
import sys
import pygame
import string
import subprocess

import Events
import Options
import ToServer

from Client import Client
client = Client()

pygame.font.init()

LEFT = TOP = 0
CENTRE = CENTER = 1
RIGHT = BOTTOM = 2

class Vertical(list):
    def __init__(self, parent, background=(0, 0, 0, 0), align=LEFT, padding=5):
        list.__init__(self)
        self.parent = parent
        self.background = background
        self.rect = pygame.Rect(0, 0, 0, 0)
        self.align = align
        self.padding = padding
        self.name=""
        
    def update(self):
        for widget in self:
            widget.update()
    
    def draw(self):
        # Initialise a new rect
        self.rect.size = (self.padding, self.padding)
        # Calculate our rect width and height
        for widget in self:
            surface, position = widget.draw()
            if position.width + self.padding * 2 > self.rect.width:
                self.rect.width = position.width + self.padding * 2
            self.rect.height += position.height + self.padding
        # Create a new surface for the container
        self.surface = pygame.Surface(self.rect.size).convert_alpha()
        self.surface.fill(self.background)
        # Keep track of the current x position for the next widget
        current = self.padding
        # Define where widgets need to go
        for widget in self:
            widget.rect.top = current
            if self.align == LEFT:
                widget.rect.left = self.padding
            if self.align == CENTRE:
                widget.rect.centerx = self.rect.width / 2
            if self.align == RIGHT:
                widget.rect.right = self.rect.width - self.padding
            surface, position = widget.draw()
            self.surface.blit(surface, position)
            current += position.height + self.padding
        return self.surface, self.rect
        
    def over(self, pos):
        x, y = pos
        x -= self.rect.x
        y -= self.rect.y
        pos = x, y
        for widget in self:
            over, local_pos = widget.over(pos)
            if over is not None:
                return over, local_pos
        return None, None
        
    def focus(self):
        return
    
    def unfocus(self):
        return
        
class Horizontal(Vertical):
    def draw(self):
        # Initialise a new rect
        self.rect.size = (self.padding, self.padding)
        # Calculate our rect width and height
        for widget in self:
            surface, position = widget.draw()
            if position.height + self.padding * 2 > self.rect.height:
                self.rect.height = position.height + self.padding * 2
            self.rect.width += position.width + self.padding
        # Create a new surface for the container
        self.surface = pygame.Surface(self.rect.size).convert_alpha()
        self.surface.fill(self.background)
        # Keep track of the current x position for the next widget
        current = self.padding
        # Define where widgets need to go
        for widget in self:
            widget.rect.left = current
            if self.align == TOP:
                widget.rect.top = self.padding
            if self.align == CENTRE:
                widget.rect.centery = self.rect.height / 2
            if self.align == BOTTOM:
                widget.rect.bottom = self.rect.height - self.padding
            surface, position = widget.draw()
            self.surface.blit(surface, position)
            current += position.width + self.padding
        return self.surface, self.rect
        
class Absolutes(Vertical):
    """Container which sizes to parent element and places children by their
    specified position"""
    def draw(self):
        # Initialise a new rect
        self.rect.size = self.parent.rect.size
        self.rect.topleft = (0, 0)
        # Calculate our rect width and height
        for widget in self:
            surface, position = widget.draw()
            if position.right > self.rect.width:
                self.rect.width = position.right
            if position.bottom > self.rect.height:
                self.rect.height = position.bottom
        # Create a new surface for the container
        self.surface = pygame.Surface(self.rect.size).convert_alpha()
        self.surface.fill(self.background)
        for widget in self:
            surface, position = widget.draw()
            self.surface.blit(surface, position)
        return self.surface, self.rect
        
class Screen(Vertical):
    """Container which sizes to parent element and centres its children, drawing
    one on top of the other"""
    def draw(self):
        # Initialise a new rect
        self.rect.size = self.parent.rect.size
        self.rect.topleft = (0, 0)
        # Create a new surface for the container
        self.surface = pygame.Surface(self.rect.size).convert_alpha()
        self.surface.fill(self.background)
        for widget in self:
            surface, position = widget.draw()
            # Centre the widget
            widget.rect.center = self.rect.center
            self.surface.blit(surface, position)
        return self.surface, self.rect
        

class ShipInfoContainer(Horizontal):
    def __init__(self, parent, ship):
        Horizontal.__init__(self, parent, (0, 0, 0, 100), align=CENTRE)
        self.ship = ship
        self.append(ShipInfo(self, ship))
        if ship == client.game.selected:
            if ship.player == client.game.players.turn:
                if ship.player == client.game.player.key():
                    self.append(Vertical(self))
                    # Add new Weapon widgets for the currently selected ship
                    self[-1].append(Weapon(self[-1], client.graphics, ship, 0, client.server))
                    self[-1].append(Weapon(self[-1], client.graphics, ship, 1, client.server))
        self.draw()
        self.update()
    
    def update(self):
        x, y = self.ship.screen_location()
        self.rect.topleft = (x - (self.rect.width - Options.TILE_WIDTH[Options.ZOOM_LEVEL]) / 2, y - self.rect.height)
        Horizontal.update(self)

class MenuContainer(Screen):
    def __init__(self, parent):
        Screen.__init__(self, parent, (0, 0, 0, 100))
        self.append(SplashBG(self))
        self.append(Absolutes(self))
        self[-1].append(PandRButton(self))
        self.events = Events.Events()
        self.main()
        self.name = "screen"
        
    def over(self, pos):
        x, y = pos
        x -= self.rect.x
        y -= self.rect.y
        pos = x, y
        for widget in reversed(self):
            over, local_pos = widget.over(pos)
            if over is not None:
                return over, local_pos
        return self, pos
        
    def close(self, *args):
        self.parent.remove(self)
        return True
    
    def main(self, *args):
        self.events.unbind(type=pygame.KEYDOWN, key=pygame.K_ESCAPE)
        try:
            self.remove(self.child)
        except AttributeError:
            pass
        self.child = Vertical(self, align=CENTRE, padding=40)
        self.child.append(HostButton(self.child))
        self.child.append(JoinButton(self.child))
        self.child.append(OptionsButton(self.child))
        self.child.append(QuitButton(self.child))
        self.append(self.child)
        client.focus(self)
        if client.game is not None:
            self.events.bind(self.close, type=pygame.KEYDOWN, key=pygame.K_ESCAPE)
        return True
        
    def join(self, *args):
        self.events.unbind(type=pygame.KEYDOWN, key=pygame.K_ESCAPE)
        self.remove(self.child)
        self.child = JoinDialog(self)
        self.append(self.child)
        self.events.bind(self.main, type=pygame.KEYDOWN, key=pygame.K_ESCAPE)
        for x in self.parent:
            if x.name == "screen":
                for y in x:
                    try:
                        if y.name == "bob":
                            x.remove(y)
                    except AttributeError:
                        pass

        return True
    
    def host(self, *args):
        self.events.unbind(type=pygame.KEYDOWN, key=pygame.K_ESCAPE)
        self.remove(self.child)
        self.child = Vertical(self.child, background=(0, 0, 0, 100), align=CENTRE)
        self.child.append(Text(self.child, "Notes"))
        self.child.append(TextInput(self.child, "Anyone can join!", 100))
        self.child.append(Spacer(self.child, (1, 10)))
        self.child.append(Text(self.child, "Port"))
        self.child.append(TextInput(self.child, "7059", 100))
        self.child.append(StartServer(self.child))
        self.append(self.child)
        self.events.bind(self.main, type=pygame.KEYDOWN, key=pygame.K_ESCAPE)
        client.focus(self.child[1])
        self.child[1].esc = self.main
        self.child[4].esc = self.main
        return True
        
    def options(self, *args):
        self.events.unbind(type=pygame.KEYDOWN, key=pygame.K_ESCAPE)
        self.remove(self.child)
        self.child = Vertical(self.child, background=(0, 0, 0, 100), align=CENTRE)
        self.child.append(Text(self.child, "Music Volume"))
        self.child.append(Slider(self.child, length=200, value=client.sounds.musvol, function=client.sounds.set_music_volume))
        self.child.append(Spacer(self.child, (1, 10)))
        self.child.append(Text(self.child, "Sound Effects Volume"))
        self.child.append(Slider(self.child, length=200, value=client.sounds.sfxvol, function=client.sounds.set_sfx_volume))
        self.append(self.child)
        self.events.bind(self.main, type=pygame.KEYDOWN, key=pygame.K_ESCAPE)
        
    def pandrlogin(self, *args):
        self.events.unbind(type=pygame.KEYDOWN, key=pygame.K_ESCAPE)
        self.remove(self.child)
        self.child = Vertical(self.child, background=(0, 0, 0, 100), align=CENTRE)
        
        
        self.child.append(Text(self.child, "Username:"))
        self.child.append(TextInputReturn(self.child, None, "username", 100))#Return blanks, -Return resets :/
        self.child.append(Spacer(self.child, (1, 10)))
        
        self.child.append(Text(self.child, "Password:"))
        self.child.append(TextInputReturnpwd(self.child, None, "", 100))
        
        self.child.append(Horizontal(self.child, background=(0, 0, 0, 0), align=CENTRE))
        self.child[-1].append(Text(self.child, "Remember?"))
        self.child[-1].append(Checkbox(self.child, True))
        self.child.append(PandRLogin(self.child))
        self.append(self.child)
        self.events.bind(self.main, type=pygame.KEYDOWN, key=pygame.K_ESCAPE)
        
        client.focus(self.child[1])
        self.child[1].esc = self.main
        self.child[4].esc = self.main
        
    
    def joinserver(self, *args):
        self.events.unbind(type=pygame.KEYDOWN, key=pygame.K_ESCAPE)
        self.remove(self.child)
        self.child = Vertical(self.child, background=(0, 0, 0, 0), align=CENTRE)
        self.child.append(Horizontal(self.child, background=(0, 0, 0, 0), align=CENTRE))
        self.child[-1].append(BePlayerOne(self.child))
        self.child[-1].append(BePlayerNone(self.child))
        self.child[-1].append(BePlayerTwo(self.child))
        self.child.append(Horizontal(self.child, background=(0, 0, 0, 0), align=CENTRE))
        self.child[-1].append(TextChatContainer(self, (200,200)))
        self.child[-1].append(Spacer(self.child, (200, 10)))
        self.child[-1].append(Text(self.child, "Player list here?"))
        self.append(self.child)
        self.events.bind(self.main, type=pygame.KEYDOWN, key=pygame.K_ESCAPE)
            
class Table(Vertical):
    def __init__(self, parent, columns, **kwargs):
        Vertical.__init__(self, parent, **kwargs)
        self.columns = [0 for column in range(columns)]
        
    def draw(self):
        # Reset all sizes to 0
        self.columns = [0 for column in range(len(self.columns))]
        # For each child
        for widget in self:
            # Ask them to calculate sizes (eventually change to widget.redraw())
            columns = widget.draw()
            # For each column
            for column in range(len(self.columns)):
                # Get the width of the widget's item in the column
                width = columns[column].get_width()
                # If widget's column's width is bigger than our column's width
                if width > self.columns[column]:
                    # Grab it
                    self.columns[column] = width
        # Calculate total width of self
        self.rect.width = self.padding
        for column in self.columns:
            self.rect.width += column + self.padding
        self.rect.height = self.padding
        for widget in self:
            # Set children's width to our width
            widget.rect.width = self.rect.width
            # Increment our height
            self.rect.height += widget.rect.height + self.padding
        self.surface = pygame.Surface(self.rect.size).convert_alpha()
        self.surface.fill(self.background)
        y = self.padding
        for widget in self:
            x = self.padding
            widget.rect.topleft = (x, y)
            # Draw each column in the right place
            columns = widget.draw()
            for column in range(len(self.columns)):
                self.surface.blit(columns[column], (x, y))
                x += self.columns[column] + self.padding
            y += widget.rect.height + self.padding
        return self.surface, self.rect
        
class JoinDialog(Vertical):
    def __init__(self, parent):
        Vertical.__init__(self, parent, background=(0, 0, 0, 0), align=CENTRE, padding=20)
        self.append(ServerInput(self))
        self.append(ServerList(self))
        self.append(Refresh(self, self[1]))
        
class ServerInput(Vertical):
    def __init__(self, parent):
        Vertical.__init__(self, parent, background=(0, 0, 0, 100), align=CENTRE, padding=5)
        self.append(Text(self, "Type the IP or host you wish to join"))
        self.append(TextInputReturn(self, self.connect, "", 100))
        client.focus(self[1])
        self[1].esc = self.parent.parent.main
        
    def connect(self, text):
        # Extract host/port from text
        if text.find(' ') != -1:
            host, port = text.split(' ')[:2]
            try:
                port = int(port)
            except ValueError:
                host, port = text, 7059
        else:
            host, port = text, 7059
        client.join(host, port)
    
    def over(self, pos):
        over, local_pos = Vertical.over(self, pos)
        if over:
            return over, local_pos
        if self.rect.collidepoint(pos):
            client.focus(self[1])
        return None, None
        
class ServerList(Table):
    def __init__(self, parent):
        Table.__init__(self, parent, 4, background=(0, 0, 0, 100), align=CENTRE, padding=5)
        self.refresh()
    
    def refresh(self):
        servers = client.database.server_list()
        del self[:]
        if servers:
            self.append(Row(self, ("Notes", "Players", "Map", "Address")))
            for server in client.database.server_list():
                self.append(ServerButton(self, server))
        else:
            self.append(Row(self, ("", "Could not find any servers online", "", "")))
            #self.append(Text(self, ("Could not find any servers")))

class Widget(object):
    """Baseclass for widgets"""
    
    font = pygame.font.Font(pygame.font.match_font('georgia'), 14)
    if (sys.platform == "darwin"):
        font = pygame.font.Font("/Library/Fonts/Georgia.ttf", 14)
    
    def __init__(self, parent, rect):
        self.parent = parent
        self.rect = rect
        self.name = ""
            
    def over(self, pos):
        x, y = pos
        if self.rect.left < 0:
            x -= self.parent.rect.left - self.rect.width
        if self.rect.top < 0:
            y -= self.parent.rect.top - self.rect.height
        if self.rect.collidepoint((x, y)):
            x -= self.rect.left
            y -= self.rect.top
            return self, (x, y)
        return None, None
    
    def click(self, pos):
        """Widget.click should return True if it doesn't grab focus but
        self if it does"""
        return
    
    def clicked(self, pos):
        """Called on a successful mousebuttondown, mousebuttonup combo"""
        return
        
    def drag(self, pos):
        """Called when mousebuttondown has happened on this widget followed by
        a mousemotion"""
        return
    
    def dragged(self, pos):
        """Called on a successful mousebuttondown, mousemotion, mousebuttonup
        combo"""
        return
        
    def draw(self):
        return self.surface, self.rect
        
    def hover(self, pos):
        """Run when the widget is hovered over"""
        return
        
    def unhover(self):
        return
        
    def focus(self):
        return
    
    def unfocus(self):
        return
    
    def update(self):
        return
        
class Text(Widget):
    """Simple widget which renders text"""
    def __init__(self, parent, text):
        self.text = text
        self.parent = parent
        self.render()
        
    def render(self):
        self.surface = self.font.render(self.text, True, (255, 255, 255))
        self.rect = self.surface.get_rect()

class TextInput(Text):
    history = []
    def __init__(self, parent, text="", minwidth=0):
        self.minwidth = minwidth
        self.place = 0
        self.cursor = len(text)
        self.events = Events.Events()
        self.events.bind(self.event, type=pygame.KEYDOWN)
        Text.__init__(self, parent, text)
        
        
    def render(self):
        if client.focused == self:
            text = self.text[:self.cursor] + "|" + self.text[self.cursor:]
        else:
            text = self.text
        surface = self.font.render(text, True, (255, 255, 255))
        width, height = surface.get_size()
        if width < self.minwidth:
            width = self.minwidth
        padding = 5
        width += padding * 2
        height += padding * 2
        self.surface = pygame.Surface((width, height)).convert_alpha()
        self.surface.fill((0, 0, 0, 0))
        pygame.draw.lines(self.surface, (255, 255, 255), False, ((padding, 0), (0, 0), (0, height - 1), (padding, height - 1)))
        pygame.draw.lines(self.surface, (255, 255, 255), False, ((width - padding - 1, 0), (width - 1, 0), (width - 1, height - 1), (width - padding - 1, height - 1)))
        self.surface.blit(surface, ((width - surface.get_width()) / 2, padding))
        self.rect = self.surface.get_rect()
    
    def click(self, pos):
        return True
        
    def focus(self):
        self.render()
    
    def unfocus(self):
        self.render()
    
    def enter(self):
        return
    
    def esc(self):
        return
    
    def event(self, event):
        #if pygame.key.name(event.key) in string.printable:
        if pygame.key.name(event.key) in string.letters + string.digits + "'.,/-" or event.key == pygame.K_SPACE:
            char = chr(event.key)
            for mod in (pygame.KMOD_LSHIFT, pygame.KMOD_RSHIFT, pygame.KMOD_SHIFT, pygame.KMOD_CAPS):
                if event.mod & mod != 0:
                    char = char.upper()
                    if char in string.digits:
                        char = u')!@\u00A3$%^&*('[int(char)]
                    if char == '/':
                        char = '?'
            self.text = self.text[:self.cursor] + char + self.text[self.cursor:]
            self.cursor += 1
            self.render()
        elif event.key == pygame.K_BACKSPACE:
            #self.text = self.text[:-1]
            self.text = self.text[:self.cursor - 1] + self.text[self.cursor:]
            if self.cursor > 0:
                self.cursor -= 1
            self.render()
        elif event.key == pygame.K_RETURN:
            self.enter()
        elif event.key == pygame.K_ESCAPE:
            self.esc()
        elif event.key == pygame.K_UP:
            self.place -= 1
            try:
                self.text = self.history[self.place]
                self.cursor = len(self.text)
                self.render()
            except:
                self.place += 1
        elif event.key == pygame.K_DOWN:
            self.place += 1
            if self.place < 0:
                self.text = self.history[self.place]
                self.cursor = len(self.text)
                self.render()
            else:
                self.place = 0
                self.cursor = 0
                self.text = ""
                self.render()
        elif event.key == pygame.K_LEFT:
            if self.cursor > 0:
                self.cursor -= 1
                self.render()
        elif event.key == pygame.K_RIGHT:
            if self.cursor < len(self.text):
                self.cursor += 1
                self.render()
        else:
            return False
        return True

class MessageInput(TextInput):
    history = []
    def __init__(self, parent, server, minwidth=0):
        TextInput.__init__(self, parent, "", minwidth)
        self.server = server
    
    def enter(self):
        # Don't send empty messages
        if len(self.text) > 0:
            self.server.send(ToServer.Say(self.text))
            self.history.append(self.text)
        self.esc()
    
    def esc(self):
        self.parent.parent.remove(self.parent)
        self.parent.remove(self)
        
class TextInputReturn(TextInput):
    def __init__(self, parent, function, text="", minwidth=0):
        TextInput.__init__(self, parent, text, minwidth)
        self.function = function
    
    def enter(self):
        self.function(self.text)
        
class TextInputReturnpwd(TextInput):
    def __init__(self, parent, function, text="", minwidth=0):
        TextInput.__init__(self, parent, text, minwidth)
        self.function = function
    
    def enter(self):
        self.function(self.text)
        
    def render(self):
        obfus = ""
        for char in self.text:
            obfus += "*"
        if client.focused == self:
            text = obfus[:self.cursor] + "|" + obfus[self.cursor:]
        else:
            text = obfus
        surface = self.font.render(text, True, (255, 255, 255))
        width, height = surface.get_size()
        if width < self.minwidth:
            width = self.minwidth
        padding = 5
        width += padding * 2
        height += padding * 2
        self.surface = pygame.Surface((width, height)).convert_alpha()
        self.surface.fill((0, 0, 0, 0))
        pygame.draw.lines(self.surface, (255, 255, 255), False, ((padding, 0), (0, 0), (0, height - 1), (padding, height - 1)))
        pygame.draw.lines(self.surface, (255, 255, 255), False, ((width - padding - 1, 0), (width - 1, 0), (width - 1, height - 1), (width - padding - 1, height - 1)))
        self.surface.blit(surface, ((width - surface.get_width()) / 2, padding))
        self.rect = self.surface.get_rect()

class MessageBox(Widget):
    """Simple messagebox widget which disappears when clicked"""
    def __init__(self, parent, message, place):
        self.message = message
        self.rect = pygame.Rect(place, (0, 0))
        self.render()
        Widget.__init__(self, parent, pygame.Rect(place, self.surface.get_size()))
            
    def click(self, pos):
        self.parent.remove(self)

    def render(self):
        padding = 10
        render = self.font.render(self.message, True, (255, 255, 255))
        width, height = render.get_size()
        width += padding * 2
        height += padding * 2
        self.surface = pygame.Surface((width, height)).convert_alpha()
        self.surface.fill((0, 0, 0, 100))
        self.surface.blit(render, (padding, padding))
        self.rect.width, self.rect.height = width, height
        
class MessageBoxNamed(MessageBox):
    def __init__(self, parent, message, name):
        MessageBox.__init__(self, parent, message, (-5, -5))
        self.name = name

class Tooltip(MessageBox):
    def hovering(self, pos):
        return False

class TimedBox(MessageBox):
    def __init__(self, parent, message):
        MessageBox.__init__(self, parent, message, (-5, -5))
        self.timeout = 0
        for widget in parent:
            if widget != self:
                if isinstance(widget, TimedBox):
                    widget.rect.move_ip(0, -self.rect.height - 5)
    
    def update(self):
        # If we've reached our final hour
        if self.timeout == Options.MESSAGEBOX_TIMEOUT:
            # Goodbye!
            self.parent.remove(self)
        self.timeout += 1
        
class TurnBox(Widget):
    def __init__(self, parent):
        self.other_textures = []
        self.your_textures = []
        for i in range(1, 5):
            self.other_textures.append(client.graphics[os.path.join("Data", "UI", "p" + str(i) + "turn.png")])
        for i in range(1, 5):
            self.your_textures.append(client.graphics[os.path.join("Data", "UI", "p" + str(i) + "yourturn.png")])
        Widget.__init__(self, parent, pygame.Rect((5, 5), self.your_textures[0].get_size()))
        
    def clicked(self, pos):
        # End turn (next player)
        client.server.send(ToServer.EndTurn())
        return
        
    def hover(self, pos):
        """Run when the widget is hovered over"""
        return
    
    def draw(self):
        if client.game.players.turn == client.game.player.key():
            return self.your_textures[client.game.players[client.game.players.turn].number], self.rect
        else:
            return self.other_textures[client.game.players[client.game.players.turn].number], self.rect
        
class Weapon(Widget):
    def __init__(self, parent, graphics, ship, weapon, server):
        x, y = ship.shadow_location()
        self.ship = ship
        self.weapon = weapon
        self.surface = graphics[os.path.join("Data", "UI",  self.ship.weapons[self.weapon].icon +".png")]
        Widget.__init__(self, parent, pygame.Rect((0, 0), self.surface.get_size()))
        self.server = server
    
    def hover(self, pos):
        """Run when the widget is hovered over"""
        # Set the tiles to draw
        client.game.targets = self.ship.weapons[self.weapon].targets
    
    def click(self, pos):
        self.server.send(ToServer.Fire(self.ship, self.weapon))
        
    def update(self):
        x, y = self.ship.shadow_location()
        self.rect.topleft = (x + self.weapon * (self.rect.width + 5), y + Options.TILE_HEIGHT[Options.ZOOM_LEVEL])

class ShipInfo(Widget):
    """Simple widget to display info on the selected ship"""
    def __init__(self, parent, ship):
        self.ship = ship
        self.padding = 10
        self.update()
        Widget.__init__(self, parent, self.rect)

    def hovering(self, pos):
        # return None to allow click-through
        return

    def update(self):
        try:
            info = self.info()
            renders = []
            width, height = 0, 0
            for line in info:
                renders.append(self.font.render(line, True, (255, 255, 255)))
                if renders[-1].get_width() > width:
                    width = renders[-1].get_width()
                height += renders[-1].get_height()
            width += self.padding * 2
            height += self.padding * 2
            self.surface = pygame.Surface((width, height)).convert_alpha()
            self.surface.fill((0, 0, 0, 0))
            y = self.padding
            for render in renders:
                self.surface.blit(render, ((width - render.get_width()) / 2, y))
                y += render.get_height()
            self.rect = pygame.Rect(0, 0, width, height)
        except KeyError:
            self.parent.parent.remove(self.parent)
    
    def info(self):
        for player in client.game.players.values():
            if self.ship.key() in player.ships:
                if player == client.game.player:
                    name = "You"
                else:
                    name = player.name
        try: 
            return ["Class: " + str(self.ship.__class__.__name__),
                    "Player: " + name,
                    "",
                    "SU: " + str(self.ship.steam) + "/" + str(self.ship.steam_max) + "/+" + str(self.ship.steam_prod),
                    "SI: " + str(self.ship.health) + "/" + str(self.ship.health_max),
                    #"SI: " + str(int(float(self.ship.health) * 100 / self.ship.health_max)) + "%",
                   ]
        except UnboundLocalError:
            print "UNBOUNDLOCAL Interfaces 775"
            return ["Class: " + str(self.ship.__class__.__name__),
                    "Player: " + "<unknown>",
                    "",
                    "SU: " + str(self.ship.steam) + "/" + str(self.ship.steam_max) + "/+" + str(self.ship.steam_prod),
                    "SI: " + str(self.ship.health) + "/" + str(self.ship.health_max),
                    #"SI: " + str(int(float(self.ship.health) * 100 / self.ship.health_max)) + "%",
                   ]


class Compass(Widget):
    def __init__(self, parent):
        self.surface = client.graphics[os.path.join("Data", "UI", "Compass.png")]
        Widget.__init__(self, parent, pygame.Rect((-5, 5), self.surface.get_size()))
        
    def draw(self):
        return self.surface, self.rect

    def hovering(self, pos):
        return

class SplashBG(Widget):
    '''General gackground, used for all menus. Yes, Ratchet is the lazy.'''
    def __init__(self, parent):
        splash = client.graphics[os.path.join("Data", "UI", "splash.jpg")]
        width, height = splash.get_size()
        if client.rect.width < width:
            height = height * client.rect.width / width
            width = client.rect.width
        # Easier just to scale by width. Height later, perhaps.
        
        self.surface = pygame.transform.smoothscale(splash, (width, height))
        Widget.__init__(self, parent, pygame.Rect((0, 0), (width, height)))
        
    def click(self, pos):
        return
        
    def draw(self):
        return self.surface, self.rect

    def hovering(self, pos):
        return
        
class MenuButton(Widget):
    """Menu button superclass"""
    def __init__(self, parent, bitmap):
        self.surface = client.graphics[os.path.join("Data", "UI", bitmap)]
        Widget.__init__(self, parent, pygame.Rect((0, 0), self.surface.get_size()))
        self.surfaces = [(self.surface, self.surface.get_size())]
        brace = client.graphics[os.path.join("Data", "UI", "brace.png")]
        # Create a new rect to size the 'hover' surface
        hover_rect = pygame.Rect(0, 0, 0, 0)
        # Calculate the height
        if brace.get_height() > self.surface.get_height():
            hover_rect.height = brace.get_height()
        else:
            hover_rect.height = self.surface.get_height()
        # Calculate the width
        hover_rect.width = brace.get_width() * 2 + 50 + self.surface.get_width()
        # Create a new surface for the render
        hover_surface = pygame.Surface(hover_rect.size).convert_alpha()
        hover_surface.fill((0, 0, 0, 0))
        # Render the button and braces
        hover_surface.blit(brace, (0, (hover_rect.height - brace.get_height()) / 2))
        hover_surface.blit(self.surface, (25 + brace.get_width(), (hover_rect.height - self.surface.get_height()) / 2))
        hover_surface.blit(pygame.transform.flip(brace, True, False), (50 + brace.get_width() + self.surface.get_width(), (hover_rect.height - brace.get_height()) / 2))
        self.surfaces.append((hover_surface, hover_rect.size))
        self.hovered = False
    
    #def hover(self, pos):
        #if not self.hovered:
        #    self.hovered = True
        #    self.surface, self.rect.size = self.surfaces[self.hovered]
            
    #def update(self):
        #if self.hover:
        #    self.hovered = False
        #    self.surface, self.rect.size = self.surfaces[self.hovered]
            
    def draw(self):
        return self.surface, self.rect
        
class Dismiss(Widget):
    '''GO AWAY'''
    def __init__(self, parent):
        self.surface = client.graphics[os.path.join("Data", "UI", "Ram.png")]
        Widget.__init__(self, parent, pygame.Rect((200, 200), self.surface.get_size()))
        
    def click(self, pos):
        # Get rid of menus, all of them.
        self.parent.esc()
        
    def hover(self, pos):
        # extra bit like 'close?'
        return
    
    def draw(self):
        return self.surface, self.rect
        
class HostButton(MenuButton):
    '''I liek to hozt plz.'''
    def __init__(self, parent):
        MenuButton.__init__(self, parent, "host.png")
        
    def click(self, pos):
        self.parent.parent.host()
        return

class QuitButton(MenuButton):
    def __init__(self, parent):
        MenuButton.__init__(self, parent, "quit.png")
    
    def click(self, pos):
        raise SystemExit
        return
        
class JoinButton(MenuButton):
    '''I liek to join plz.'''
    def __init__(self, parent):
        MenuButton.__init__(self, parent, "join.png")
        self.box = MessageBoxNamed(self.parent.parent, "Loading server list...", "bob")
        
    def click(self, pos):
        
        self.parent.parent.append(self.box)
        '''while (1):
            for item in self.parent:
                print "a",
                if item == self.box:
                    break;
        '''
        client.queue.append("""for x in self:
            if x.name == \"screen\":
                x.join()""")
        return
        
class OptionsButton(MenuButton):
    def __init__(self, parent):
        MenuButton.__init__(self, parent, "options.png")
        
    def click(self, pos):
        self.parent.parent.options()
        return
    
        
class Row(Widget):
    def __init__(self, parent, columns):
        Widget.__init__(self, parent, pygame.Rect(0, 0, 0, 0))
        self.columns = columns
        self.render()
    
    def render(self):
        self.surfaces = []
        self.rect.height = 0
        for column in self.columns:
            self.surfaces.append(self.font.render(column, True, (255, 255, 255)))
            if self.surfaces[-1].get_height() > self.rect.height:
                self.rect.height = self.surfaces[-1].get_height()
            
    def draw(self):
        return self.surfaces
        
class ServerButton(Row):
    def __init__(self, parent, server):
        self.server = server
        columns = [server['notes'], str(len(server['users'])), server['map'], server['address'] + ":" + server['port']]
        Row.__init__(self, parent, columns)
        
    def click(self, pos):
        client.join(self.server['address'], int(self.server['port']))
        

'''class ImgButton(Widget):
    def __init__(self, parent, img):
        self.surface = client.graphics[os.path.join("Data", "UI",  img)]
        Widget.__init__(self, parent, pygame.Rect((0, 0), self.surface.get_size()))
        self.parent = parent
'''
class StartServer(Widget):
    def __init__(self, parent):
        self.surface = client.graphics[os.path.join("Data", "UI",  "startserver.png")]
        Widget.__init__(self, parent, pygame.Rect((0, 0), self.surface.get_size()))
        self.parent = parent
    
    def click(self, pos):
        try:
            port = int(self.parent[4].text)
        except ValueError:
            port = 7059
            print "Port is default, 7059."
        client.server_process = subprocess.Popen(["python", os.path.join("Server", "Server.py"), str(port), self.parent[1].text])
        #Need to kill it afterwards :/
        pygame.time.wait(10)
        client.join("localhost", port)
        return

class PandRLogin(Widget):
    def __init__(self, parent):
        self.surface = client.graphics[os.path.join("Data", "UI",  "login.png")]
        Widget.__init__(self, parent, pygame.Rect((0, 0), self.surface.get_size()))
        self.parent = parent
    
    
    def click(self, pos):
        #print "Sending data", "["+self.parent[1].text+"]", "["+self.parent[4].text+"]", "R?", self.parent[5][1].value
        client.database.loginbynum(self.parent, self.parent[1].text, self.parent[4].text,self.parent[5][1].value)
        #if (self.parent[5][1].value == True):
            #rememebr in Options? Write out to file?
        #Could also wait on received data, lol.
        return

class PandRButton(Widget):
    def __init__(self, parent):
        self.surface = client.graphics[os.path.join("Data", "UI",  "pandrsmall.png")]
        self.rect = pygame.Rect((0, 0), self.surface.get_size())
        Widget.__init__(self, parent, self.rect)
        self.parent = parent
    
    def click(self, pos):
        self.parent.pandrlogin()
        #self.parent.joinserver()
        return
        
    def draw(self):
        return self.surface, self.rect
        
class BackButton(Widget):
    def __init__(self, parent, function):
        self.surface = client.graphics[os.path.join("Data", "UI",  "back.png")]
        self.rect = pygame.Rect((0, 0), self.surface.get_size())
        Widget.__init__(self, parent, self.rect)
        self.parent = parent
        self.function = function
    
    def click(self, pos):
        exec(self.function)
        return
        
class Slider(Widget):
    def __init__(self, parent, length=100, value=1.0, function=None):
        self.length = length
        # function will be called each time the slider's value changes
        self.function = function
        self.value = value
        self.slide = pygame.Surface((length, 10)).convert_alpha()
        self.slide.fill((0, 0, 0, 0))
        pygame.draw.line(self.slide, (200, 200, 200), (0, 5), (length, 5))
        self.slider = pygame.Surface((10, 10)).convert_alpha()
        self.slider.fill((200, 200, 200))
        self.slider_rect = pygame.Rect(0, 0, 10, 10)
        Widget.__init__(self, parent, self.slide.get_rect())
        self.render()
        
    def drag(self, pos):
        x, y = pos
        value = float(x - 5) / (self.length - 10)
        if value < 0:
            value = 0.0
        elif value > 1:
            value = 1.0
        self.value = value
        if self.function:
            self.function(self.value)
        self.render()
    
    def hover(self, pos):
        if self.slider_rect.collidepoint(pos):
            self.slider.fill((255, 255, 255))
            self.render()
        else:
            self.unhover()
    
    def unhover(self):
        self.slider.fill((200, 200, 200))
        self.render()
    
    def render(self):
        self.slider_rect.left = self.value * (self.length - 10)
        self.surface = self.slide.copy()
        self.surface.blit(self.slider, self.slider_rect.topleft)
    
    def draw(self):
        return self.surface, self.rect
        
        
class VertSlider(Widget):
    def __init__(self, parent, height=100, value=1.0, function=None):
        print "VertSlider"
        self.height = height
        # function will be called each time the slider's value changes
        self.function = function
        self.value = value
        self.slide = pygame.Surface((10, self.height)).convert_alpha()
        self.slide.fill((0, 0, 0, 0))
        pygame.draw.line(self.slide, (200, 200, 200), (5, 0), (5, height))
        self.slider = pygame.Surface((10, 10)).convert_alpha()
        self.slider.fill((200, 200, 200))
        self.slider_rect = pygame.Rect(0, 0, 10, 10)
        Widget.__init__(self, parent, self.slide.get_rect())
        self.render()
        
    def drag(self, pos):
        x, y = pos
        value = float(y - 5) / (self.height - 10)
        if value < 0:
            value = 0.0
        elif value > 1:
            value = 1.0
        self.value = value
        if self.function:
            self.function(self.value)
        self.render()
    
    def hover(self, pos):
        if self.slider_rect.collidepoint(pos):
            self.slider.fill((255, 255, 255))
            self.render()
        else:
            self.unhover()
    
    def unhover(self):
        self.slider.fill((200, 200, 200))
        self.render()
    
    def render(self):
        self.slider_rect.top = self.value * (self.height - 10)
        self.surface = self.slide.copy()
        self.surface.blit(self.slider, self.slider_rect.topleft)
    
    def draw(self):
        return self.surface, self.rect        







class ChatList(Table):
    def __init__(self, parent, rows=10, width=200):
        self.history = client.chathistory
        self.rows = rows
        self.top = len(self.history)-self.rows
        self.bottom = self.top+self.rows
        Table.__init__(self, parent, 2, background=(0, 0, 0, 100), align=CENTRE, padding=5)
        self.refresh()
    
    def refresh(self):
        print "UPDATED"
        while len(self) > 0:
            self.pop()
        self.history = client.chathistory
        self.append(Row(self, ("Name:", "Message:")))
        for x in range(self.top, self.bottom):
            try:
                self.append(Row(self, (self.history[x][0]+": ", self.history[x][1])))
            except IndexError:
                #self.append(Row(self, ("-", "-")))
                pass
            
    def scroll(self, value):
        self.top = int((len(self.history)-self.rows) * value)
        self.bottom = self.top + self.rows
        
        print "SCROLLED", self.top, self.bottom
        self.refresh()
        

class TextChat(Horizontal):
    #chat history table and scroll vertslider
    def __init__(self, parent, size):
        Horizontal.__init__(self, parent, background=(0, 0, 0, 100), align=CENTRE, padding=4)
        chat = ChatList(self)
        self.append(chat)
        client.chat = chat
        self.append(VertSlider(self, size[1], 1, self[0].scroll))
        self.padding = 2

        
class ChatInputReturn(TextInput):
    def __init__(self, parent, text="", minwidth=0):
        TextInput.__init__(self, parent, text, minwidth)
        self.history = []
        self.parent = parent
        self.server = client.server
    
    def enter(self):
        # Don't send empty messages
        if len(self.text) > 0:
            self.server.send(ToServer.Say(self.text))
            self.history.append(self.text)
            self.text = ""
            print client.chathistory
        #self.parent[0].refresh()

class TextChatContainer(Vertical):
    #textchat and input bar
    def __init__(self, parent, size):
        Vertical.__init__(self, parent, background=(0, 0, 0, 100), align=CENTRE, padding=4)
        chatsize = (size[0]-1, size[1])
        self.append(TextChat(self, chatsize))
        self.append(ChatInputReturn(self, "", size[1]))
        self.padding = 2
        self.name="-TCC-"







        
class Spacer(Widget):
    def __init__(self, parent, size, background=(0, 0, 0, 0)):
        Widget.__init__(self, parent, pygame.Rect((0, 0), size))
        self.surface = pygame.Surface(size).convert_alpha()
        self.surface.fill(background)
    
    def draw(self):
        return self.surface, self.rect
        

class Checkbox(Widget):
    def __init__(self, parent, value = False):
        self.surface = client.graphics[os.path.join("Data", "UI", "checkbox.png")]
        self.rect = pygame.Rect((0, 0), (12,12))
        Widget.__init__(self, parent, self.rect)
        self.surfaces = []
        self.surfaces.append(self.surface.subsurface(self.rect))
        self.rect.move_ip(12,0)
        self.surfaces.append(self.surface.subsurface(self.rect))

        self.value = value
    
    def click(self, pos):
        self.value = not self.value
            
    def draw(self):
        return self.surfaces[int(self.value)], self.rect


class HoverButton(Widget):
    def __init__(self, parent, image, staypressed = False, group = ""):
        self.surface = client.button_graphics.__load__(image)
        self.rect = self.surface[0][0].get_rect()
        Widget.__init__(self, parent, self.rect)
        self.currentsurface = 0
        self.staypressed = staypressed
        self.isclicked = False
        self.group = group
        self.parent = parent
        
    def hover(self, pos):
        if self.staypressed and self.isclicked:
            self.currentsurface = 2
            #print "stick"
        else:
            self.currentsurface = 1
    
    def unhover(self):
        if self.staypressed and self.isclicked:
            self.currentsurface = 2
            #print "stick"
        else:
            self.currentsurface = 0
            #print "reset"
            self.isclicked = False
        
    def click(self, pos):
        if self.staypressed == False or self.isclicked == False:
            self.clickfunction()
            self.currentsurface = 2
            #print "down"
            self.isclicked = True
            for list in self.parent:
                for widge in list:
                    try:
                        if widge.group == self.group and self.group != "" and widge != self:
                            widge.currentsurface = 0
                            widge.isclicked = False
                            
                    except AttributeError:
                        pass;
        
    def draw(self):
        return self.surface[self.currentsurface][0], self.rect
        
        

class Refresh(Widget):
    def __init__(self, parent, torefresh):
        self.surface = client.graphics[os.path.join("Data", "UI", "refresh.png")]
        self.rect = pygame.Rect((0, 0), self.surface.get_size())
        Widget.__init__(self, parent, self.rect)
        self.torefresh=torefresh
    
    def click(self, pos):
        self.parent.parent.append(MessageBoxNamed(self.parent.parent, "Loading server list...", "bob"))
        client.queue.append("""for x in self:
            if x.name == \"screen\":
                x.join()""")


        
class BePlayerOne(HoverButton):
    def __init__(self, parent):
         HoverButton.__init__(self, parent, "p1button.png", True, "playerchoice")
    def clickfunction(self):
        print "I want to be player 1!"
        client.server.send(ToServer.ChoosePlayer(1))
        
class BePlayerTwo(HoverButton):
    def __init__(self, parent):
         HoverButton.__init__(self, parent, "p2button.png", True, "playerchoice")
    def clickfunction(self):
        print "I want to be player 2!"
        client.server.send(ToServer.ChoosePlayer(2))
        
class BePlayerNone(HoverButton):
    def __init__(self, parent):
         HoverButton.__init__(self, parent, "p0button.png", True, "playerchoice")
    def clickfunction(self):
        print "I don't mind which player I am!"
        client.server.send(ToServer.ChoosePlayer(0))

